﻿// 文件读取in2
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using static AdjPlane.Angle_t;
using static AdjPlane.AdjCmn;

namespace AdjPlane
{
    using obs_dic = Dictionary<string, double>;
    using sta_obs_dic = Dictionary<string, Dictionary<string, double>>;

    //读取文件
    public partial class Plane
    {
        readonly char[] splitRow = { '\r', '\n' };//\r,\n表示回车和换行，用于分割每一行
        readonly char[] splitCol = { ',', '，', '\t', ' ' };//用于分割每一列，\t:制表符

        protected int SideSign = 0;
        //读in2
        protected void ReadFile(string path,Proc_t popt)  // 读取并存储数据
        {
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);//注册gb2312  
            string file = File.ReadAllText(path, Encoding.GetEncoding("gb2312"));
            List<Obs> raw = new List<Obs>();

            string station = string.Empty;//测站
            string[] lines = mysplit(file, splitRow);
            string[] line0 = mysplit(lines[0], splitCol);//标称精度
            if (string.IsNullOrWhiteSpace(line0[0]))
                return;
            alpha = double.Parse(line0[0].Trim());//方向精度
            msa = double.Parse(line0[1].Trim());//固定误差
            msb = double.Parse(line0[2].Trim());//比例误差

            int nl0=0, ns0=0;//单测站观测值个数
            
            for (int i = 1; i < lines.Length; i++)//从第二行开始
            {
                if (string.IsNullOrWhiteSpace(lines[i]))//
                    continue;
                if (lines[i].Contains("#"))  //注释说明
                    continue;
                if (lines[i].Contains("Gyro"))        /* 是否使用陀螺边数据 */
                {
                    string[] line = mysplit(lines[i], splitCol);
                    sigt = double.Parse(line[1]);
                    continue;
                }

                //以下是已知信息，测站，观测数据
                if (lines[i].Contains(",") || lines[i].Contains("，"))//中英文逗号
                {//不含","的是测站行，反之是已知点或观测数据，
                    string[] line = mysplit(lines[i], splitCol);
                    if (line[2].Contains("T") && line.Length>=4)
                    {
                        //陀螺边 
                        GyroAzi tla = new GyroAzi
                        {
                            beg = line[0].Trim(),
                            end = line[1].Trim(),
                            gyazi = double.Parse(line[3].Trim())
                        };
                        if (line.Length == 5)
                            tla.adpin = double.Parse(line[4].Trim());
                        Gyro.Add(tla);
                        continue;
                    }

                    if (line.Length==3 && line[1].Trim().ToUpper() != "L" && line[1].Trim().ToUpper() != "S")
                    {   
                        //已知点信息
                        Point2D kp = new Point2D
                        {
                            X = double.Parse(line[1]),
                            Y = double.Parse(line[2])
                        };
                        knownPoint.Add(line[0].Trim(), kp);
                    }
                    else
                    {   
                        //观测值
                        string name = line[0].Trim();
                        switch (line[1].Trim().ToUpper())
                        {
                            case "L"://角度观测值
                                {
                                    int id = -1;
                                    // 当前测站观测值中是否存在当前照准点名称
                                    for(int k = 0; k < raw.Count; k++)
                                    {
                                        if (raw[k].name == name)
                                        {
                                            id = k;
                                            break;
                                        }
                                    }
                                    if(id==-1)
                                    {
                                        Obs o = new Obs();
                                        o.name = name;
                                        o.angle= double.Parse(line[2].Trim());
                                        if (line.Length == 4)
                                        {
                                            o.side = int.Parse(line[3].Trim());
                                            SideSign = 1;
                                        }
                                        raw.Add(o);
                                        nl0++;nl++;
                                    }
                                    else
                                    {
                                        raw[id].angle= double.Parse(line[2].Trim());
                                        if (line.Length == 4)
                                        {
                                            raw[id].side = int.Parse(line[3].Trim());
                                            SideSign = 1;
                                        }
                                        nl0++;nl++;
                                    }
                                    break;
                                }
                            case "S"://距离观测值
                                {
                                    int id= -1;
                                    for (int k = 0; k < raw.Count; k++)
                                    {
                                        if (raw[k].name == name)
                                        {
                                            id = k;
                                            break;
                                        }
                                    }
                                    if (id == -1)
                                    {
                                        Obs o = new Obs();
                                        o.name = name;
                                        o.distance = double.Parse(line[2].Trim());
                                        raw.Add(o);
                                        ns0++;ns++;
                                    }
                                    else
                                    {
                                        raw[id].distance = double.Parse(line[2].Trim());
                                        ns0++;ns++;
                                    }
                                    break;
                                }
                        }
                    }
                }
                else 
                {
                    //测站
                    if (raw.Count != 0)
                    {
                        Sta s = new Sta();
                        s.name = station;
                        s.data = raw;
                        s.nl = nl0;
                        s.ns = ns0;
                        AllObs.Add(s);
                        raw = new List<Obs>();
                    }
                    ns0 = 0;nl0 = 0;
                    station = lines[i].Trim();
                }
            }

            //最后一个测站的数据
            if (raw.Count != 0)  
            {
                Sta s = new Sta();
                s.name = station;
                s.data = raw;
                s.nl = nl0;
                s.ns = ns0;
                AllObs.Add(s);
            }

            ////照准点排序
            //for(int i = 0; i < AllObs.Count; i++)
            //{
            //    Sta S = AllObs[i];
            //    SortAim(S);
            //}
            //Adderror(20);

            //分开两类观测值
            obsS = GenObsS(global_popt.AveDis);
            obsL = GenObsL();

            for(int i = 0; i < Gyro.Count; i++)
            {
                int ids = FindStaName(Gyro[i].beg);
                int ido = FindObsName(ids, Gyro[i].end);
                AllObs[ids].data[ido].gyro = Gyro[i].gyazi;
            }

            //测站，点名存储
            foreach (var p in knownPoint)
            {
                PointName.Add(p.Key);
            }
            for (int i = 0; i < AllObs.Count; i++)
            {
                string staName = AllObs[i].name;
                CZ.Add(staName);
                if (!PointName.Contains(staName))
                    PointName.Add(staName);
                for(int j=0;j<AllObs[i].data.Count;j++)
                {
                    string obsName = AllObs[i].data[j].name;
                    if (!PointName.Contains(obsName))
                        PointName.Add(obsName);
                }
            }

            //所有点，未知点建立索引
            int ukp_index = 0, p_index = 0;
            foreach (var p in knownPoint)
            {
                pointIndex.Add(p.Key, p_index);
                p_index++;
            }
            foreach (string item in PointName)
            {
                if (!knownPoint.ContainsKey(item))
                {
                    pointIndex.Add(item, p_index);
                    p_index++;
                    //存储未知点,建立未知参数序列，为后续误差方程铺垫
                    ukpIndex.Add(item, ukp_index);
                    ukp_index++;
                }
            }

            ukp_num = ukpIndex.Count;//未知点的数目
            p_num = pointIndex.Count;//所有点的数量
            t = 2 * ukp_num + obsL.Count;
            nt = Gyro.Count;
            n = nl + ns;
            if(popt.GyOpt.UseGyro==1)
                n += nt;
        }

        void Adderror(double bias)
        {
            for(int i = 0; i < AllObs.Count; i++)
            {
                for(int j = 0; j < AllObs[i].data.Count; j++)
                {
                    if(AllObs[i].nl!=0 && AngleExist(i, j) == 1)
                    {
                        AllObs[i].data[j].angle = D2DMS(DMS2D(AllObs[i].data[j].angle) +Math.Pow(-1,j)*bias/3600);
                    }
                }
            }


        }
        void ReadApprox(string path)   //根据已知的近似坐标计算
        {
            if (File.Exists(path) == false)
                return;
            string file = File.ReadAllText(path, Encoding.GetEncoding("gb2312"));
            string[] lines = mysplit(file, splitRow);
            int i;
            for(i = 0; i < lines.Length; i++)
            {
                if (string.IsNullOrWhiteSpace(lines[i]))//
                    continue;
                string[] str = mysplit(lines[i], splitCol);
                
                if (str.Length == 3)
                {
                    if (IsNumber(str[1]) == 1 && IsNumber(str[2]) == 1)
                    {
                        string name = str[0].Trim();
                        if (Approx.ContainsKey(name))
                            continue;
                        double x = double.Parse(str[1].Trim());
                        double y = double.Parse(str[2].Trim());
                        Approx.Add(name, new Point2D(x, y));
                    }
                }
            }
            int len = Approx.Count;
            CopyApprox = new Point_t[len];
            i = 0;
            foreach (KeyValuePair<string, Point2D> p in Approx)
            {
                //C#实例化自定义数组，必须实例化数组中的每一个类，否则NULL
                CopyApprox[i] = new Point_t
                {
                    x = p.Value.X,
                    y = p.Value.Y,
                    name = p.Key
                };
                i++;
            }
        }

        //照准点根据测角大小排序
        void SortAim(Sta S)
        {
            for(int i = 0; i < S.data.Count-1; i++)
            {
                for(int j = i + 1; j < S.data.Count; j++)
                {
                    int ids = FindStaName(S.name);
                    if (AngleExist(ids, i) == 0 && AngleExist(ids, j) == 1)
                    {
                        Obs tmp = S.data[i];
                        S.data[i] = S.data[j];
                        S.data[j] = tmp;
                        continue;
                    }
                    if (S.data[i].angle > S.data[j].angle)
                    {
                        Obs tmp = S.data[i];
                        S.data[i] = S.data[j];
                        S.data[j] = tmp;
                    }
                }
            }
        }
        //生成obsS，ave=1，往返测据取平均
        sta_obs_dic GenObsS(int ave)
        {
            sta_obs_dic obsS = new sta_obs_dic();
            ns = 0;
            for(int i = 0; i < AllObs.Count; i++)
            {
                var data = AllObs[i].data;
                string staName = AllObs[i].name;
                obs_dic Sdata = new obs_dic();

                for(int j = 0; j < data.Count; j++)
                {
                    string obsName = data[j].name;
                    int ido = 0, ids = 0;
                    double dis;

                    if (Dis(i, j) == 0) continue;

                    if (Aim(obsName, staName, ref ido, ref ids) == 1)
                    {
                        if (Dis(ido, ids) != 0)
                        {
                            data[j].comego = 1;
                            AllObs[ido].data[ids].comego = 1;
                            dis = (Dis(i, j) + Dis(ido, ids)) * 0.5;
                        }
                        else
                            dis = Dis(i, j);
                    }
                    else
                        dis = Dis(i, j);

                    if (ave == 0)
                    {
                        Sdata.Add(obsName, Dis(i, j));
                        ns++;
                    }
                    else
                    {
                        if (obsS.ContainsKey(obsName))  //存在返测结果说明，已经往返测取平均了
                        {
                            if (obsS[obsName].ContainsKey(staName))
                                continue;
                        }
                        Sdata.Add(obsName, dis);
                        ns++;
                    }                        
                }
                if (Sdata.Count == 0) continue;
                obsS.Add(staName, Sdata);
            }
            return obsS;
        }
        //生成obsL
        sta_obs_dic GenObsL()
        {
            sta_obs_dic obsL=new sta_obs_dic();
            nl = 0;

            for(int i = 0; i < AllObs.Count; i++)
            {
                string staName = AllObs[i].name;
                var data = AllObs[i].data;
                obs_dic Ldata = new obs_dic();
                for(int j = 0; j < data.Count; j++)
                {
                    string obsName = data[j].name;
                    if (AllObs[i].nl>0 && AngleExist(i, j) == 1)
                    {
                        Ldata.Add(obsName, Angle(i, j));
                        nl++;
                    }
                }
                if (Ldata.Count == 0) continue;
                obsL.Add(staName, Ldata);
            }
            return obsL;
        }

        static string[] mysplit(string line, char[] split)
        {
            return line.Split(split, StringSplitOptions.RemoveEmptyEntries);
        }
    }
}
